<template>
	<view class="content">
		<text class="text-tips">诶呀，被殷宝找到了隐藏的宝藏。这是一个谜题：约翰内斯·维米尔最出名的代表作是什么？\n答案是一张正方形的图片，上传后会自动识别相似度。</text>
		<button @click="chooseImage" type="primary" class="btn" v-bind:disabled="!canUpLoad">上传</button>
		<text class="text-sim">图片相似度为{{sim}}%</text>
		<button type="primary" class="btn" v-if="sim>70" @click="toGift">获得隐藏礼物🎁</button>
		<text class="message-box">{{message}}</text>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				message: "Console\n",
				img1: "",
				img2: "",
				str1: "",
				str2: "",
				sim: 0,
				canUpLoad:false
			}
		},
		onLoad() {
			var self = this
			this.getImgToBase64('/ywwbirthdaygift/static/compare.jpeg', function(data) {
				self.img1 = self.dataURLtoFile(data, 'img1');
				self.readFile(self.img1)
					.then(r => {
						return self.compressImage(r)
					})
					.then(r => {
						let info = self.grayImage(r.imageData);
						self.str1 = self.HashFingerprint(info.imageData)
						self.message += "---内置图片读取成功---\n"
						self.canUpLoad = true
					})
			});
		},
		methods: {
			toGift() {
				uni.navigateTo({
					url: '/pages/index/index',
				});
			},
			getImgToBase64(url, callback) { //将图片转换为Base64
				var canvas = document.createElement('canvas'),
					ctx = canvas.getContext('2d'),
					img = new Image;
				img.crossOrigin = 'Anonymous';
				img.onload = function() {
					canvas.height = img.height;
					canvas.width = img.width;
					ctx.drawImage(img, 0, 0);
					var dataURL = canvas.toDataURL('image/jpeg');
					callback(dataURL);
					canvas = null;
				};
				img.src = url;
			},
			dataURLtoFile(dataurl, filename) { //将base64转换为文件
				var arr = dataurl.split(','),
					mime = arr[0].match(/:(.*?);/)[1],
					bstr = atob(arr[1]),
					n = bstr.length,
					u8arr = new Uint8Array(n);
				while (n--) {
					u8arr[n] = bstr.charCodeAt(n);
				}
				return new File([u8arr], filename, {
					type: mime
				});
			},
			computeSim() {
				let hm = this.getHm(this.str1, this.str2);
				let sim = this.getSimilarity(this.str1.length, hm);
				return sim
			},
			chooseImage() {
				self = this
				uni.chooseImage({
					count: 1, //默认9
					sizeType: ['original'], //可以指定是原图还是压缩图，默认二者都有
					sourceType: ['album'], //从相册选择
					success: function(res) {
						self.img2 = res.tempFiles[0]
						self.readFile(self.img2)
							.then(r => {
								return self.compressImage(r)
							})
							.then(r => {
								let info = self.grayImage(r.imageData);
								self.str2 = self.HashFingerprint(info.imageData)
								self.message += "---选择图片成功---\n"
								self.message += "---计算相似度中---\n"
								self.sim = self.computeSim()
								self.message += "---计算成功---\n"
							})
					}
				});
			},
			readFile(file) {
				return new Promise((resolve) => {
					const reader = new FileReader();
					reader.readAsDataURL(file);
					reader.addEventListener("load", function() {
						resolve(reader.result);
					}, false)
				})
			},
			compressImage(imgSrc, imgWidth = 50) {
				return new Promise((resolve, reject) => {
					if (!imgSrc) {
						reject('imgSrc can not be empty!')
					}
					const canvas = document.createElement('canvas')
					const ctx = canvas.getContext('2d')
					const img = new Image()
					img.crossOrigin = 'Anonymous'
					img.src = imgSrc
					img.onload = function() {
						canvas.width = imgWidth
						canvas.height = imgWidth
						ctx.drawImage(img, 0, 0, imgWidth, imgWidth)
						const imageData = ctx.getImageData(0, 0, imgWidth, imgWidth)
						let info = {
							dataUrl: canvas.toDataURL(),
							imageData,
						}
						resolve(info)
					}
				})
			},
			//根据rgb值算出灰度值
			getGrayFromRGB(R, G, B) {
				let a = Math.pow(R, 2.2) + Math.pow(1.5 * G, 2.2) + Math.pow(0.6 * B, 2.2);
				let b = 1 + Math.pow(1.5, 2.2) + Math.pow(0.6, 2.2);
				return parseInt(Math.pow(a / b, 1 / 2.2))
			},
			//根据rgba数组生成 imageData 和dataUrl
			createImageData(data) {
				const canvas = document.createElement('canvas')
				canvas.width = 50
				canvas.height = 50
				const ctx = canvas.getContext('2d')
				const imgWidth = Math.sqrt(data.length / 4)
				const newImageData = ctx.createImageData(imgWidth, imgWidth)
				for (let i = 0; i < data.length; i += 4) {
					newImageData.data[i] = data[i]
					newImageData.data[i + 1] = data[i + 1]
					newImageData.data[i + 2] = data[i + 2]
					newImageData.data[i + 3] = data[i + 3]
				}
				ctx.putImageData(newImageData, 0, 0);
				return {
					dataUrl: canvas.toDataURL(),
					imageData: newImageData
				}
			},
			//灰度化
			grayImage(imageData) {
				let data = imageData.data;
				let len = imageData.data.length;
				let newData = new Array(len);
				for (let i = 0; i < len; i += 4) {
					const R = data[i];
					const G = data[i + 1];
					const B = data[i + 2];
					const grey = this.getGrayFromRGB(R, G, B);
					newData[i] = grey;
					newData[i + 1] = grey;
					newData[i + 2] = grey;
					newData[i + 3] = 255;
				}
				return this.createImageData(newData);
			},
			HashFingerprint(imageData) {
				const grayList = imageData.data.reduce((pre, cur, index) => {
					if ((index + 1) % 4 === 0) {
						pre.push(imageData.data[index - 1])
					}
					return pre
				}, [])
				const length = grayList.length
				const grayAverage = grayList.reduce((pre, next) => (pre + next), 0) / length
				return grayList.map(gray => (gray >= grayAverage ? 1 : 0)).join('')
			},
			getHm(str1, str2) {
				let distance = 0;
				let len = str1.length;
				for (let i = 0; i < len; i++) {
					if (str1[i] != str2[i]) {
						distance++;
					}
				}
				return distance
			},
			//相似度
			getSimilarity(strLen, hm) {
				return parseInt((strLen - hm) / strLen * 100)
			}
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.btn {
		margin-top: 50rpx;
		width: 400rpx;
	}

	.text-sim {
		margin-top: 50rpx;
		outline-style: dashed;
		outline-color: #a278fe;
		padding: 10rpx;
		outline-width: 8rpx;
	}

	.message-box {
		margin-top: 50rpx;
		text-align: center;
		outline-style: dashed;
		outline-color: #fc4943;
		padding: 10rpx;
		outline-width: 8rpx;
	}

	.text-tips {
		word-break: break-all;
	}
</style>
